package com.ruowei.modules.sys.service;

import com.ruowei.common.error.StorageException;
import com.ruowei.common.error.exception.DataNotFoundException;
import com.ruowei.config.ApplicationProperties;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class FileService {

    private static final Logger log = LoggerFactory.getLogger(FileService.class);
    private final Path uploadDir;

    public FileService(ApplicationProperties properties) {
        this.uploadDir = Paths.get(properties.getFile().getUploadDir());
        init(properties.getFile().getUploadDir());
    }

    public Resource loadAsResource(Path rootLocation, String filename) {
        try {
            Path file = rootLocation.resolve(filename).normalize();
            Resource resource = new UrlResource(file.toUri());
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new DataNotFoundException("未找到文件" + filename);
            }
        } catch (MalformedURLException e) {
            throw new DataNotFoundException("未找到文件" + filename);
        }
    }

    public FileInfo store(MultipartFile file) {
        String filename = StringUtils.cleanPath(
                file.getOriginalFilename() == null ? file.getName() : file.getOriginalFilename());
        try {
            if (file.isEmpty()) {
                throw new StorageException("无法保存空文件：" + filename);
            }
            if (filename.contains("..")) {
                // This is a security check
                throw new StorageException("无法将文件保存到指定路径外：" + filename);
            }
            String extension = FilenameUtils.getExtension(filename);
            String originName = FilenameUtils.getBaseName(filename);
            File newFile = new File(String.valueOf(this.uploadDir.resolve(originName + "." + extension)));
            while (newFile.exists()) {
                int randomNum = RandomUtils.nextInt(1, 1000);
                newFile = new File(String.valueOf(
                        this.uploadDir.resolve(originName + randomNum + "." + extension)));
            }
            Files.copy(file.getInputStream(), newFile.toPath());
            String path = newFile.getName();
            String name = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
            return new FileInfo(name, path);
        } catch (IOException e) {
            log.info("保存文件失败：{}，异常信息：{}", filename, e.getCause());
            throw new StorageException("保存文件失败：" + filename);
        }
    }

    public Resource loadResource(String filename) {
        try {
            Path file = uploadDir.resolve(filename);
            Resource resource = new UrlResource(file.toUri());
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new StorageException("读取文件失败：" + filename);
            }
        } catch (MalformedURLException e) {
            log.info("读取文件失败：{}，异常信息：{}", filename, e.getCause());
            throw new StorageException("读取文件失败：" + filename);
        }
    }

    public Resource downloadResource(String url) {
        try {
            Resource resource = new UrlResource(url);
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new StorageException("下载文件失败：" + url);
            }
        } catch (MalformedURLException e) {
            log.info("下载文件失败：{}，异常信息：{}", url, e.getCause());
            throw new StorageException("下载文件失败：" + url);
        }
    }

    public void init(String uploadDir) {
        try {
            if (!new File(uploadDir).exists()) {
                Files.createDirectories(this.uploadDir);
            }
        } catch (IOException e) {
            log.info("创建文件夹失败，异常信息：", e.getCause());
            throw new StorageException("无法创建文件夹：" + this.uploadDir);
        }
    }

    public class FileInfo {
        private String name;
        private String path;

        public FileInfo(String name, String path) {
            this.name = name;
            this.path = path;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }
    }
}
